﻿using System;

namespace InDepth2Demo.Chapter1314
{
    // 在委托中使用可变性
    // delegate T Fun<out T>()
    // delegate void Action<in T>(T obj)

    internal class VarianceInDelegate
    {
        //用 Func<T> 和 Action<T> 委托演示可变性
        public static void Call()
        {
            Func<Square> squareFactory = () => new Square(new Point(5, 5), 10);
            Func<IShape> shapeFactory = squareFactory;                          // 使用协变性转换 Func<T>

            Action<IShape> shapePrinter = shape => Console.WriteLine(shape.Area);
            Action<Square> squarePrinter = shapePrinter;                        // 使用逆变性转换 Action<T>

            squarePrinter(squareFactory());         // 完整性检查   
            shapePrinter(shapeFactory());
        }

        //当然，  这里我们只使用了包含单一类型参数的委托。那么对于多个类型参数的委托和接口将会是什么情况呢？如果类型参数本身就是泛型委托，又会是什么情况呢？情况可能会变得很复杂。

        // 13.3.4  复杂情况
        // 1. Converter<TInput, TOutput>：同时使用协变性和逆变性
        // 用简单的类型演示协变性和逆变性
        public static void Call2()
        {
            Converter<object, string> converter = x => x.ToString();
            Converter<string, string> contravariance = converter;       //逆变性  TInput 类型参数只用于输入，因此可以逆变地将 Converter<object,string> 当作 Converter<Button,string> 来使用。
            Converter<object, object> covariance = converter;           //协变性  同样，TOutput类型参数只用于输出（返回类型），因此可以协变地使用它
            Converter<string, object> both = converter;                 //逆变与协变
        }

        //2. 疯狂的高阶函数
        // 让我们来看以下4个委托声明：
        delegate Func<T> FuncFunc<out T>();
        delegate void ActionAction<out T>(Action<T> Action);
        delegate void ActionFunc<in T>(Func<T> function);
        delegate Action<T> FuncAction<in T>();

        // 每一个声明都相当于将一个标准的委托嵌入到另一个之中。例如，FuncAction<T>等同于Func<Action<T>>，它们都表示一个函数，返回以T为参数的Action。
        // 但它应该是协变的还是逆变的呢？这个函数将返回与T相关的内容，似乎应该是协变的，但是它也传入了与T有关的内容，似乎又是逆变的。答案是该委托对T是逆变的，因此声明时使用了in修饰符。
    }
}
